﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using HtmlAgilityPack;
using ObservadorPeplau.API;
using ObservadorPeplau.API.Business;
using ObservadorPeplau.Usercontrols;

namespace ObservadorPeplau
{
    public partial class Dashboard : Form
    {
        private int _numberOfStaredLoaded;
        private bool _staredLoaded;
        private bool _homepageLoaded;
        private List<Discussion> _updatesNew;
        private List<Discussion> _updatesFeatured;
        private List<Discussion> _updatesStared;
        private FormWindowState _previousWindowState;
        private readonly Loading _loadingControl = new Loading();
        private BackgroundWorker _homepageBackgroundWorker = new BackgroundWorker();

        private int IntervalSeconds
        {
            get
            {
                int interval = 0;
                if (!int.TryParse(txbRefreshInterval.Text, out interval))
                    return 60;
                return interval;
            }
            set { txbRefreshInterval.Text = value.ToString(); }
        }

        public Dashboard()
        {
            InitializeComponent();
        }

        private void LoadHomepageBackground()
        {
            _updatesNew = new List<Discussion>();
            _updatesFeatured = new List<Discussion>();
            _homepageLoaded = false;

            _homepageBackgroundWorker = new BackgroundWorker();
            _homepageBackgroundWorker.DoWork += homepageBackgroundWorker_DoWork;
            _homepageBackgroundWorker.RunWorkerCompleted += homepageBackgroundWorker_RunWorkerCompleted;
            _homepageBackgroundWorker.RunWorkerAsync();
        }

        private void Dashboard_Load(object sender, EventArgs e)
        {
            ConfigureHomepageGrids();
            LoadHomepageDiscussionsFromRegistry();
            LoadHomepageBackground();

            ConfigureStaredDiscussionsGrid();
            LoadStaredDiscussions();

            ConfigureRefreshTimer();
            ConfigureCommentTree();
        }

        private void homepageBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            HomepageManager.LoadHomePage();
        }
        private void homepageBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BindHomepageDiscussions();
        }

        private void ConfigureStaredDiscussionsGrid()
        {
            if (StaredDiscussions.StarClickEventHandler == null)
                StaredDiscussions.StarClickEventHandler += OnDiscussionStarClick;
            if (StaredDiscussions.DoubleClickEventHandler == null)
                StaredDiscussions.DoubleClickEventHandler += OnDiscussionDoubleClick;
            if (StaredDiscussions.ClickEventHandler == null)
                StaredDiscussions.ClickEventHandler += OnDiscussionClick;
        }

        private void LoadStaredDiscussion(Discussion discussion)
        {
            if (discussion.IsStared)
            {
                // Add if its a stared discussion
                var discussionBackgroundWorker = new BackgroundWorker();
                discussionBackgroundWorker.DoWork += discussionBackgroundWorker_DoWork;
                discussionBackgroundWorker.RunWorkerCompleted += discussionBackgroundWorker_RunWorkerCompleted;
                discussionBackgroundWorker.RunWorkerAsync(discussion);
            }
            else
            {
                // Else remove from grid
                StaredDiscussions.Delete(discussion);
            }
        }

        private void LoadStaredDiscussions()
        {
            _updatesStared = new List<Discussion>();
            _numberOfStaredLoaded = 0;
            _staredLoaded = false;
         
            // Get stared discussions from registry and bind them all at once to the grid
            var lstMarkedDiscussions = DiscussionManager.GetMarked(Constants.DiscussionStaredKey);

            if (StaredDiscussions.Discussions==null)
                StaredDiscussions.Discussions = new List<Discussion>();
            StaredDiscussions.Syncronize(lstMarkedDiscussions);

            // For each Stared Discussion, load comments in a new thread
            foreach (Discussion discussion in lstMarkedDiscussions)
                LoadStaredDiscussion(discussion);
        }

        private void discussionBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var discussion = (Discussion) e.Argument;
            discussion.Comments = DiscussionManager.GetCommentsFromWeb(discussion.Url);
            e.Result = discussion;
        }
        private void discussionBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Update stared discussions
            var thisDiscussion = (Discussion) e.Result;
            StaredDiscussions.Syncronize(thisDiscussion);

            // Add to the list of discussions
            if (thisDiscussion.HasUnreadComments)
                _updatesStared.Add(thisDiscussion);

            // Show Ballom if needed
            _numberOfStaredLoaded++;
            if (StaredDiscussions.Discussions.Count > 0 && _numberOfStaredLoaded == StaredDiscussions.Discussions.Count)
            {
                _staredLoaded = true;
                ShowNotifyIcon();
            }

            // Update News and Featured discussions
            if (FeaturedDiscussions.Discussions.Count(p=>p.Url==thisDiscussion.Url)>0)
                FeaturedDiscussions.Syncronize(thisDiscussion);
            if (NewDiscussions.Discussions.Count(p => p.Url == thisDiscussion.Url) > 0)
                NewDiscussions.Syncronize(thisDiscussion);
        }

        private string GetDiscussionTitleForNotify(Discussion discussion)
        {
            var title = "- "+discussion.Title;
            if (title.Length > 50)
                title = title.Substring(0, 50) + "...";
            title += " ("+discussion.GetUnreadComments().Count.ToString()+")";
            return title;
        }

        private void ShowNotifyIcon()
        {
            if (!_homepageLoaded || !_staredLoaded || WindowState!=FormWindowState.Minimized)
                return;

            var sb = new StringBuilder();
            if (_updatesFeatured.Count>0)
            {
                var msgTitle = "Novas discussões em destaque: ";
                if (_updatesFeatured.Count==1)
                    msgTitle = "Nova discussão em destaque: ";
                sb.AppendLine(msgTitle.ToUpper());
                foreach (Discussion discussion in _updatesFeatured)
                    sb.AppendLine(GetDiscussionTitleForNotify(discussion));
            }

            if (_updatesNew.Count > 0)
            {
                var msgTitle = "Novas discussões: ";
                if (_updatesNew.Count == 1)
                    msgTitle = "Nova discussão: ";
                sb.AppendLine(msgTitle.ToUpper());
                foreach (Discussion discussion in _updatesNew)
                    sb.AppendLine(GetDiscussionTitleForNotify(discussion));
            }

            if (_updatesStared.Count > 0)
            {
                var msgTitle = "Discussões com estrela: ";
                if (_updatesStared.Count == 1)
                    msgTitle = "Discussão com estrela: ";
                sb.AppendLine(msgTitle.ToUpper());
                foreach (Discussion discussion in _updatesStared)
                    sb.AppendLine(GetDiscussionTitleForNotify(discussion));
            }

            if (sb.Length > 0)
            {
                notify.BalloonTipText = "";
                notify.BalloonTipText += sb.ToString();
                notify.Visible = true;
                notify.ShowBalloonTip(0);
            }
        }

        private void ConfigureHomepageGrids()
        {
            FeaturedDiscussions.GridViewType = View.Tile;
            if (FeaturedDiscussions.DoubleClickEventHandler == null)
                FeaturedDiscussions.DoubleClickEventHandler += OnDiscussionDoubleClick;
            if (FeaturedDiscussions.StarClickEventHandler == null)
                FeaturedDiscussions.StarClickEventHandler += OnDiscussionStarClick;

            if (NewDiscussions.DoubleClickEventHandler == null)
                NewDiscussions.DoubleClickEventHandler += OnDiscussionDoubleClick;
            if (NewDiscussions.StarClickEventHandler == null)
                NewDiscussions.StarClickEventHandler += OnDiscussionStarClick;
        }

        private void LoadHomepageDiscussionsFromRegistry()
        {
            FeaturedDiscussions.Discussions = DiscussionManager.GetMarked(Constants.FeaturedDiscussionsKey);
            FeaturedDiscussions.Bind();

            NewDiscussions.Discussions = DiscussionManager.GetMarked(Constants.NewDiscussionsKey);
            NewDiscussions.Bind();
        }

        private void ConfigureRefreshTimer()
        {
            TimerRefresh.Interval = IntervalSeconds * 1000;
            TimerRefresh.Enabled = chbAutoRefresh.Checked;
        }

        private void BindHomepageDiscussions()
        {
            // Bind FeaturedDiscussions Control
            var featuredDiscussions = HomepageManager.GetFeaturedDiscussions();
            if (FeaturedDiscussions.Discussions == null || FeaturedDiscussions.Discussions.Count == 0)
            {
                FeaturedDiscussions.Discussions = featuredDiscussions;
                FeaturedDiscussions.Bind();
            }
            else
                FeaturedDiscussions.Syncronize(featuredDiscussions);

            // Bind NewDiscussions Control
            var newDiscussions = HomepageManager.GetNewDiscussions();
            if (NewDiscussions.Discussions == null || NewDiscussions.Discussions.Count == 0)
            {
                NewDiscussions.Discussions = newDiscussions;
                NewDiscussions.Bind();
            }
            else
                NewDiscussions.Syncronize(newDiscussions);            

            // Add Updates to list to show in a ballon
            var lstUpdatedFeatured = FeaturedDiscussions.Discussions.Where(p=>!p.IsStared && !p.IsRead);
            var lstUpdatedNew = NewDiscussions.Discussions.Where(p => !p.IsStared && !p.IsRead);
            foreach (Discussion discussion in lstUpdatedFeatured)
                _updatesFeatured.Add(discussion);
            foreach (Discussion discussion in lstUpdatedNew)
                _updatesNew.Add(discussion);

            // Show Notify
            _homepageLoaded = true;
            ShowNotifyIcon();

            // Save lists on registry
            DiscussionManager.ClearMark(Constants.FeaturedDiscussionsKey);
            featuredDiscussions.ForEach(p => DiscussionManager.SetMarked(p, Constants.FeaturedDiscussionsKey, true));
            DiscussionManager.ClearMark(Constants.NewDiscussionsKey);
            newDiscussions.ForEach(p => DiscussionManager.SetMarked(p, Constants.NewDiscussionsKey, true));
        }

        private void RefreshDiscussions()
        {
            LoadHomepageBackground();
            LoadStaredDiscussions();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshDiscussions();
        }

        public void OnDiscussionStarClick(DiscussionGrid grid, Discussion selected)
        {
            if (selected == null)
                return;

            LoadHomepageBackground();
            LoadStaredDiscussion(selected);
        }

        private void ConfigureCommentTree()
        {
            if (CommentTree.TreeNodesChanged==null)
                CommentTree.TreeNodesChanged += CommentTreeChanged;
            if (CommentTree.NodeMouseHover == null)
                CommentTree.NodeMouseHover += CommentTreeNodeMouseHover;
            if (CommentTree.TreeMouseLeave == null)
                CommentTree.TreeMouseLeave += CommentTreeMouseLeave;            
        }

        public void CommentTreeMouseLeave(CommentTree tree)
        {
            CommentDetails.LoadComment(null);
            CommentDetails.Visible = false;
        }

        public void CommentTreeNodeMouseHover(CommentTree tree, TreeNode node, Comment comment)
        {
            if (CommentDetails.Comment==null || comment.Id != CommentDetails.Comment.Id)
            {
                CommentDetails.LoadComment(comment);
                CommentDetails.Visible = true;

                // Tree Position absolutelly on form
                Point treeLocationOnForm = MainBrowser.PointToClient(Cursor.Position);

                int x = MainBrowser.Width - CommentDetails.Width;
                CommentDetails.Location = new Point(x, treeLocationOnForm.Y);
            }
        }

        public void CommentTreeChanged(CommentTree tree)
        {
            LoadHomepageBackground();

            LoadStaredDiscussion(tree.Discussion);
        }

        public void OnDiscussionClick(DiscussionGrid grid, Discussion selectedDiscussion)
        {
            if (selectedDiscussion == null)
                return;

            _loadingControl.ShowLoading(CommentTree);

            CommentTree.Discussion = selectedDiscussion;
            CommentTree.Bind();

            _loadingControl.CloseLoading();
        }

        public void OnDiscussionDoubleClick(DiscussionGrid grid, Discussion selected)
        {
            if (selected == null)
                return;
            MainBrowser.Navigate(selected.Url);
        }

        private void MainBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            _loadingControl.ShowLoading(MainBrowser);
        }

        private void MainBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            if (MainBrowser.ReadyState == WebBrowserReadyState.Complete)
            {
                // Hide loader
                _loadingControl.CloseLoading();

                // Get doc from browser
                var doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(MainBrowser.DocumentText);

                // Remove FB:LIKE control
                var divs = doc.DocumentNode.SelectNodes("//div[@style='float: right']");
                var hasChanges = false;
                if (divs!=null)
                    foreach (HtmlNode div in divs)
                    {
                        var likes = div.ChildNodes.Where(p => p.Name == "fb:like");
                        if (likes.Count() > 0)
                        {
                            div.RemoveAllChildren();
                            hasChanges = true;
                        }
                    }
                
                // Fix relative images
                if (hasChanges)
                {
                    var images = doc.DocumentNode.SelectNodes("//img");
                    if (images != null)
                        foreach (HtmlNode image in images)
                        {
                            string imageUrl = image.Attributes["src"].Value;
                            var uri = new Uri(imageUrl, UriKind.RelativeOrAbsolute);

                            if (!uri.IsAbsoluteUri)
                            {
                                uri = new Uri(MainBrowser.Url, uri);
                                image.Attributes["src"].Value = uri.ToString();
                            }
                        }
                }

                // Update browser content
                if (hasChanges)
                    MainBrowser.DocumentText = doc.DocumentNode.InnerHtml;
            }
        }

        private void chbAutoRefresh_CheckedChanged(object sender, EventArgs e)
        {
            TimerRefresh.Enabled = chbAutoRefresh.Checked;
        }

        private void txbRefreshInterval_TextChanged(object sender, EventArgs e)
        {
            ConfigureRefreshTimer();
        }

        private void TimerRefresh_Tick(object sender, EventArgs e)
        {
            RefreshDiscussions();
        }

        private void Dashboard_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                Hide();
                ShowInTaskbar = false;
            }
            else
                _previousWindowState = WindowState;
        }

        private void NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            BringAppFromIconTray();
        }

        private void BringAppFromIconTray()
        {
            Show();
            WindowState = _previousWindowState;
            ShowInTaskbar = true;
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            BringAppFromIconTray();
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void notify_BalloonTipClicked(object sender, EventArgs e)
        {
            BringAppFromIconTray();
        }
    }
}
